package com.dflc.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dflc.common.CommonConstant;
import com.dflc.entity.po.TBackLoginUser;
import com.dflc.entity.po.TLog;
import com.dflc.entity.rep.HttpResponseEntity;
import com.dflc.entity.req.BackUserReq;
import com.dflc.entity.req.LoginReq;
import com.dflc.entity.vo.LoginUserInfoVo;
import com.dflc.service.TBackLoginUserService;
import com.dflc.mapper.TBackLoginUserMapper;
import com.dflc.service.TLogService;
import com.dflc.utils.RedisUtil;
import com.dflc.utils.SM4;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Date;

/**
* @author 86158
* @description 针对表【t_back_login_user(后台管理员账号)】的数据库操作Service实现
* @createDate 2024-11-27 10:54:12
*/
@Service
public class TBackLoginUserServiceImpl extends ServiceImpl<TBackLoginUserMapper, TBackLoginUser>
    implements TBackLoginUserService{
    // 最大尝试次数
    @Value("${loginLimit.loginCount}")
    private  int MAX_ATTEMPTS;
    // 锁定时间（秒）
    @Value("${loginLimit.loginTime}")
    private  int LOCK_TIME;
    @Value("${sm4.secretKey}")
    private String secretKey;
    @Resource
    private TLogService tLogService;
    @Resource
    private RedisUtil redisUtil;
    @Override
    public HttpResponseEntity login(LoginReq req,String clientIp) {
        try {
            // 1. 检查登录限制
            int remainingTime = checkLoginAllowed(clientIp, req.getUserName());
            if (remainingTime > 0) {
                return HttpResponseEntity.error2(401, "您的账号已被锁定，请" + remainingTime + "秒后再试！",remainingTime);
            }
            String userName = req.getUserName();

            //1、去数据库查询 SELECT * FROM ums_member WHERE username = ? OR mobile = ?
            TBackLoginUser loginUser = this.baseMapper.selectOne(new LambdaQueryWrapper<TBackLoginUser>()
                    .eq(TBackLoginUser::getUserName, userName).or().eq(TBackLoginUser::getPhone, userName)
                    .eq(TBackLoginUser::getState, CommonConstant.StateActive.Active));
            if (loginUser == null) {
                // 记录失败尝试
                recordLoginFailure(clientIp, req.getUserName());
                // 获取剩余尝试次数
                int attempts = getCurrentAttempts(clientIp, req.getUserName());
                int remainingAttempts = MAX_ATTEMPTS - attempts;
                if (remainingAttempts <= 0){
                    remainingAttempts=0;
                }
                if (remainingAttempts==0){
                    return HttpResponseEntity.error2(401, "您的账号已被锁定，请60秒后再试！",60);
                }
                return HttpResponseEntity.error(401, "用户名或密码错误，您还有" + remainingAttempts + "次尝试机会！");
            } else if (CommonConstant.StateActive.Deleted == loginUser.getState()) {
                return HttpResponseEntity.error(500, "该用户已经失效！");
            } else {
                //获取到数据库里的password
                //进行密码匹配
                boolean equals = SM4.encryptECB(req.getPassword(), secretKey).equals(loginUser.getPassword());
                if (equals) {
                    //登录成功
                    Date d = new Date();

                    LoginUserInfoVo userInfo = new LoginUserInfoVo();
                    userInfo.setUserName(loginUser.getUserName());
                    userInfo.setName(loginUser.getName());
                    userInfo.setId(Math.toIntExact(loginUser.getId()));
                    userInfo.setPhone(loginUser.getPhone());
                    userInfo.setUnitId(loginUser.getUnitId());
                    userInfo.setDepartmentId(loginUser.getDepartmentId());
                    userInfo.setIsAdmin(loginUser.getIsAdmin());
                    userInfo.setLastLoginTime(d);
                    if (ObjectUtils.isEmpty(loginUser.getLastLoginTime())) {
                        userInfo.setFirst(true);
                    }else {
                        userInfo.setFirst(false);
                    }
                    StpUtil.login(userInfo.getId());
                    StpUtil.getSession().set(CommonConstant.SESSION_USER_KEY, userInfo);
                    userInfo.setSatoken(StpUtil.getTokenValue());

//                    //记录登录日志star
                    TLog tLog = new TLog();
                    tLog.setUserId(userInfo.getId());
                    tLog.setOperation("login");
                    tLog.setType(CommonConstant.LogType.Rep);
                    tLog.setDescription("登陆成功");
                    tLog.setTimestamp(new Date());
                    tLogService.saveLog(tLog);
                    // 3. 登录成功，清除记录
                    clearLoginRecord(clientIp, req.getUserName());
//                    //记录登录日志end
                    return HttpResponseEntity.success(userInfo);
                } else {
                    // 记录失败尝试
                    recordLoginFailure(clientIp, req.getUserName());
                    // 获取剩余尝试次数
                    int attempts = getCurrentAttempts(clientIp, req.getUserName());
                    int remainingAttempts = MAX_ATTEMPTS - attempts;
                    if (remainingAttempts <= 0){
                        remainingAttempts=0;
                    }
                    if (remainingAttempts==0){
                        return HttpResponseEntity.error2(401, "您的账号已被锁定，请60秒后再试！",60);
                    }
                    return HttpResponseEntity.error(401, "用户名或密码错误，您还有" + remainingAttempts + "次尝试机会！");
                }
            }

        } catch (Exception e) {
            return HttpResponseEntity.error(500, e.toString());
        }
    }


    @Override
    public HttpResponseEntity findUserByUserName(BackUserReq req) {
        try {
            if (!req.getPassword().equals(req.getConfirmPassword())) {
                return HttpResponseEntity.error(500, "两次输入的密码不一致,请重新输入");
            }

            //1、去数据库查询 SELECT * FROM ums_member WHERE username = ? OR mobile = ?
            TBackLoginUser sysLoginUser = this.baseMapper.selectOne(new LambdaQueryWrapper<TBackLoginUser>()
                    .eq(TBackLoginUser::getUserName, req.getUserName()).or().eq(TBackLoginUser::getPhone, req.getUserName())
                    .eq(TBackLoginUser::getState, CommonConstant.StateActive.Active));
            if (sysLoginUser == null) {
                return HttpResponseEntity.error(500, "该用户不存在！");
            } else if (CommonConstant.StateActive.Deleted == sysLoginUser.getState()) {
                return HttpResponseEntity.error(500, "该用户已经失效！");
            }

            sysLoginUser.setPassword(SM4.encryptECB(req.getPassword(), secretKey));
            sysLoginUser.setUpdateTime(new Date());
            this.baseMapper.updateById(sysLoginUser);

            return HttpResponseEntity.success("更新密码成功！");
        } catch (Exception e) {
            return HttpResponseEntity.error(500, e.toString());
        }
    }

    @Override
    public HttpResponseEntity findUserIsAdminByUserId(Integer userId) {
       try {
           TBackLoginUser tBackLoginUser = this.getById(userId);
           if (tBackLoginUser == null) {
               return HttpResponseEntity.error(500, "查询不到该用户的信息！请检查数据！");
           } else if (tBackLoginUser.getState() == CommonConstant.StateActive.Deleted) {
               return HttpResponseEntity.error(500, "当前用户已被删除！");
           }
           return HttpResponseEntity.success(tBackLoginUser);
       }catch (Exception e){
           return HttpResponseEntity.error(500, e.toString());
       }
    }





    /**
     * 检查是否允许登录
     * @param ip 客户端IP
     * @param account 账号
     * @return 返回剩余等待时间（秒），0表示可以登录
     */
    public int checkLoginAllowed(String ip, String account) {
        String key = buildKey(ip, account);
        if (redisUtil.hasKey(key)){
            Object o = redisUtil.get(key);
            Integer attempts = Integer.parseInt(o.toString());
            if (attempts != null && attempts >= MAX_ATTEMPTS) {
                Long expire = redisUtil.getExpire(key);
                if (expire != null && expire > 0) {
                    return expire.intValue();
                }
            }
            return 0;
        }else {
            return 0;
        }
    }

    /**
     * 记录登录失败
     * @param ip 客户端IP
     * @param account 账号
     */
    public  void recordLoginFailure(String ip, String account) {
        String key = buildKey(ip, account);
        // 使用增量操作，如果key不存在会自动设置为1
        if (redisUtil.hasKey(key)){
            Object o = redisUtil.get(key);
            int attempts = Integer.parseInt(o.toString())+1;
            redisUtil.set(key, attempts,LOCK_TIME);
        }else {
            redisUtil.set(key, 1, LOCK_TIME);
        }
    }

    /**
     * 清除登录失败记录（登录成功时调用）
     * @param ip 客户端IP
     * @param account 账号
     */
    public  void clearLoginRecord(String ip, String account) {
        // 构建登录失败记录的key
        String key = buildKey(ip, account);
        // 删除登录失败记录
        redisUtil.del(key);
    }


    /**
     * 获取当前失败次数
     * @param ip 客户端IP
     * @param account 账号
     * @return 失败次数
     */
    public int getCurrentAttempts(String ip, String account) {
        String key = buildKey(ip, account);
        Object o = redisUtil.get(key);
        Integer attempts = Integer.parseInt(o.toString());
        return attempts == null ? 0 : attempts;
    }

    private String buildKey(String ip, String account) {
//        return "login:limit:" + ip + ":" + account;
        return "login:" + ip + ":"+ account;
    }
}




